// 装饰者可用于为对象增加功能，可以替代大量子类
// 进一步分析第7章所讲的自行车商店的例子
// 顾客可以购买的自行车有4种型号，商店为每一种自行车提供一些特色配件，如前灯、尾灯、前挂货栏或铃铛等。
// 这个问题最基本的解决办法是为选件的每一种组合创建一个子类
var AcmeComfortCruiser = function() {};
var AcmeComfortCruiserWithHeadlight = function() {};
var AcmeComfortCruiserWithTaillight = function() {};
var AcmeComfortCruiserWithHeadlightAndTaillight = function() {};
var AcmeComfortCruiserWithBasket = function() {};
var AcmeComfortCruiserWithHeadlightAndBasket = function() {};
//...
// 用装饰器实现再合适不过，只需创建4个新类（一个类针对一个选件）
/* The Bicycle interface. */
var Bicycle = new Interface('Bicycle', ['assemble', 'wash', 'ride', 'repair', 'getPrice']);
// 所有自行车类和选件装饰者都要实现这个接口
/* The AcmeComfortCruiser class. */
var AcmeComfortCruiser = function() {	// implements Bicycle
	//...
};
AcmeComfortCruiser.prototype = {
	assemble: function() {},
	wash: function() {},
	ride: function() {},
	repair:function() {},
	getPrice: function() {
		return 399.00;
	}
}
/* The BicycleDecorator abstract decorator class. */
var BicycleDecorator = function(bicycle) {	// implement bicycle
	Interface.ensureImplements(bicycle, Bicycle);
	this.bicycle = bicycle;
}
BicycleDecorator.prototype = {
	assemble: function() {
		return bicycle.assemble();
	},
	wash: function() {
		return bicycle.wash();
	},
	ride: function() {
		return bicycle.ride();
	},
	repair:function() {
		return bicycle.repair();
	},
	getPrice: function() {
		return bicycle.getPrice();
	}
}
/* HeadlightDecorator class */
var HeadlightDecorator = function(bicycle) {
	HeadlightDecorator.superclass.constructor.call(this, bicycle);
}
extend(HeadlightDecorator BicycleDecorator);	// Extend the superclass
HeadlightDecorator.prototype.assemble = function() {
	return this.bicycle.assemble() + ' Attach headlight to handlebars.';
};
HeadlightDecorator.prototype.getPrice = function() {
	return this.bicycle.getPrice() + 15.00;
};
// 怎么使用装饰者，如何创建一辆带前灯的自行车
var myBicycle = new AcmeComfortCruiser();
alert(myBicycle.getPrice());
myBicycle = new HeadlightDecorator(myBicycle);
alert(myBicycle.getPrice());
// 同理创建尾灯、前挂货栏或铃铛等装饰

// 方法性能分析器
// 我们将先创建一个实现了计时功能的速成版装饰者，然后再将其改造为通用型装饰者
// 需要一个用来测试的样例类
// ListBuilder类就用于这个目的，其唯一功能是在网页上创建一个有序列表
/* ListBuilder class. */
var ListBuilder = function(parent, listLength) {
	this.parentEl = $(parent);
	this.listLength = listLength;
};
ListBuilder.prototype = {
	buildList: function() {
		var list = document.createElement('ol');
		this.parentEl.appendChild(list);

		for (var i=0; i<this.listLength; i++) {
			var item = document.createElement('li');
			list.appendChild(item);
		}
	}
};
// 我们首先要创建一个专用于这个ListBuilder类的装饰者，将记录执行buildList方法所耗用的时间。
// 用console.log输出这些结果
/* SimpleProfiler class. */
var SimpleProfile = function(component) {
	this.component = component;
};
SimpleProfile.prototype = {
	buildList: function() {
		var startTime = new Date();
		this.component.buildList();
		var elapsedTime = (new Date()).getTime() - startTime.getTime();
		console.log('buildList: ' + elapsedTime + ' ms');
	}
};
// SimpleProfiler是ListBuilder的一个装饰者。它也实现了ListBuilder中的buildList这个方法，并且在传递该方法调用的语句前后添加了一些计时用的代码。
// 调用SimpleProfiler的方法时，将输入调用组件的同名方法所耗费的时间。
// 为了测试这个装饰者，我们可以创建一个包含5000个元素的列表，看看要花多长时间：
var list = new ListBuilder('list-container', 5000);
list = new SimpleProfiler(list);
list.buildList();
// 要考虑如何对其进行通用化改造，使其可用于任何对象。必须让装饰者逐一检查组件对象的所有属性，为找到的每一个方法创建一个通道。
// 这些通道方法也必须包含启动和停止计时器的代码
/* MethodProfiler class */
var MethodProfiler = function(component) {
	this.component = component;
	this.timers = {};

	for (var key in this.component) {
		if (typeof this.component[key] !== 'function') {
			continue;
		}

		var that = this;
		(function(methodName) {
			that[methodName] = function() {
				that.startTimer(methodName);
				var returnValue = that.component[methodName].apply(that.component, arguments);
				that.displayTime(methodName, that.getElapsedTime(methodName));
				return returnValue;
			};
		})(key); 
	}
};
MethodProfiler.prototype = {
	startTimer: function(methodName) {
		this.timers[methodName] = (new Date()).getTime();
	},
	getElapsedTime: function(methodName) {
		return (new Date()).getTime() - this.timers[methodName];
	},
	displayTime: function(methodName, time) {
		console.log(methodName + ': ' + time + ' ms');
	}
};
// 用MethodProfiler对象来装饰ListBuilder
var list = new ListBuilder('list-container', 5000);
list = new MethodProfiler(list);
list.buildList('ol');
list.buildList('ul');
list.removeList('ul');
list.removeList('ol');
